package com.woniu.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.user.controller.form.ModifyVenueForm;
import com.woniu.user.controller.form.UpdatePassForm;
import com.woniu.user.controller.form.VenueLoginForm;
import com.woniu.user.controller.form.VenueRegisterForm;
import com.woniu.user.dao.AccountDao;
import com.woniu.user.exception.WebException;
import com.woniu.user.exception.WebExceptionCode;
import com.woniu.user.model.Account;
import com.woniu.user.model.Venue;
import com.woniu.user.dao.VenueDao;
import com.woniu.user.service.PicService;
import com.woniu.user.service.VenueService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.user.service.dto.AccountDto;
import com.woniu.user.service.dto.VenueDto;
import com.woniu.user.util.BeanCopyUtil;
import com.woniu.user.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.Cookie;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 场馆表 服务实现类
 * </p>
 *
 * @author Silas
 * @since 2023-02-15
 */
@Service
@Slf4j
public class VenueServiceImpl extends ServiceImpl<VenueDao, Venue> implements VenueService {


    @Resource
    private VenueDao venueDao;
    @Autowired
    private JavaMailSender javaMailSender;
    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private PicService picService;

    /**
     * @param venueLoginForm
     * @return
     */
    @Override
    public Cookie venueLogin(VenueLoginForm venueLoginForm) {
        Venue venue = getOne(new QueryWrapper<Venue>().eq("account_name", venueLoginForm.getAccountName()));
        //1.判断场馆账号名是否存在？
        if (ObjectUtils.isEmpty(venue)) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        //2.判断场馆账号名是否可用？
        if ("不可用".equals(venue.getState())) throw new WebException(WebExceptionCode.USER_IS_NOT_AVAILABLE);
        //3.判断密码是否正确
        if (!venue.getPassword().equals(venueLoginForm.getPassword()))
            throw new WebException(WebExceptionCode.PASSWORD_IS_NOT_RIGHT);
        //4.发放令牌
        Map<String, Object> map = new HashMap<>();
        map.put("venue_id", venue.getVenueId());
        String token = JwtUtil.getToken(map, 3);
        Cookie cookie = new Cookie("token", token);//生成令牌
        cookie.setMaxAge(30 * 60);//有效期30分钟
        return cookie;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void venueRegister(VenueRegisterForm venueRegisterForm) throws MessagingException {
        Venue accountName = query().eq("account_name", venueRegisterForm.getAccountName()).one();
        Assert.isNull(accountName, "用户名已存在");//判断用户是否已存在
        Venue newVenue = BeanCopyUtil.copyObject(venueRegisterForm, Venue.class);
        //newVenue.setType(); TODO
        newVenue.setState("不可用");
        Venue venue = this.getOne(new QueryWrapper<Venue>().eq("email", newVenue.getEmail()));
        if (venue != null) throw new WebException(WebExceptionCode.EMAIL_IS_EXISTS);
        save(newVenue);
        Venue one = getOne(new QueryWrapper<Venue>().eq("email", newVenue.getEmail()));
        Integer accountId = one.getVenueId();
        MimeMessage message = javaMailSender.createMimeMessage();
        message.setFrom(new InternetAddress("xuxilin1997@163.com"));//设置发送者
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(venueRegisterForm.getEmail()));//设置接收者
        //考虑点击超链接时，要带一个唯一的条件，只有这样才做到去激活一个确定的账户
        message.setContent("<a href='http://192.168.10.39:8080/venue/venueActive/" + accountId + "'>点击激活</a>", "text/html;charset=utf-8");//设置邮件内容

        message.setSubject("用户激活");
        javaMailSender.send(message);

        //检测是否注册成功
        org.springframework.messaging.Message<String> build = MessageBuilder.withPayload(venueRegisterForm.getEmail()).build();
        SendResult sendResult = rocketMQTemplate.syncSend("venueregister-check-topic", build, 30000L, 5);
        log.info("注册申请:{}", sendResult);
    }

    @Override
    public void venueActive(Integer id) {
        Venue venueDb = getById(id);
        venueDb.setState("可用");
        updateById(venueDb);
    }

    @Override
    public void closeRegister(String email) {
        Venue venue = getOne(new QueryWrapper<Venue>().eq("email", email));
        if (Objects.isNull(venue)) {
            log.warn("账户不存在", venue);

            return;
        }
        if (venue.getState().equals("不可用")) {
            log.info("注册取消:{}", venue);
            removeById(venue);

        } else {
            //若成功则发送欢迎邮件,否则移除该账号
            SendResult sendResult1 = rocketMQTemplate.syncSend("venueregister-success-topic", venue);
            log.info("注册结果消息:{}", sendResult1);
        }
    }

    @Override
    public boolean update(UpdatePassForm updatePassForm) {
        UpdateWrapper<Venue> uw = new UpdateWrapper<>();
        uw.eq("account_name", updatePassForm.getAccountName()).eq("password", updatePassForm.getOldPassword()).set("password", updatePassForm.getNewPassword());
        boolean b = update(uw);
        return b;
    }

    @Override
    public Page<Venue> query(String condition, Integer current, Integer size) {
        //配置分页片段
        Page<Venue> page = new Page<>(current == null ? 1 : current, size == null ? 4 : size);
        //配置queryWrapper
        QueryWrapper<Venue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("state", "可用");
        //判断condition是否为空，为空则findAll,不为空则条件查询
        if (!"".equals(condition) || condition != null) {
            //配置queryWrapper查询条件
            queryWrapper.eq("name", condition)   //条件查询
                    .or().like("address", condition)   //模糊查询
                    .or().eq("phone", condition)
                    .or().eq("account_name", condition)
                    .or().eq("email", condition);

        }
//生成分页
        Page<Venue> venuePage = venueDao.selectPage(page, queryWrapper);


        return venuePage;
    }


    //发送找回验证码
    @Override
    public void emailCode(String email) {
        Venue venue = this.getOne(new QueryWrapper<Venue>().eq("email", email));
        if (venue == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        if (!email.equals(venue.getEmail())) throw new WebException(WebExceptionCode.EMAIL_NOT_MATCH);
        String code = RandomUtil.randomNumbers(6);
        String title = "验证码";
        String content = "您的验证码是：" + code + "十分钟有效";
        String[] param = {email, title, content};
        SendResult sendResult = rocketMQTemplate.syncSend("code-topic", param);// 参数为tag与消息体
        log.info(sendResult.toString());// 输出发送消息的返回结果
        this.saveCode(email, code);
    }


    //收到验证码并验证
    @Override
    public void receivedCode(String email, String code) {
        if (email == null || code == null) throw new WebException(WebExceptionCode.PARAM_NULL);
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        String codes = operations.get(email);
        if (codes == null || !codes.equals(code)) throw new WebException(WebExceptionCode.CODE_INCORRECT);
    }

    //重置密码
    @Override
    public void resetPwd(VenueRegisterForm venueRegisterForm) {
        String email = venueRegisterForm.getEmail();
        String password = venueRegisterForm.getPassword();
        if (email == null || password == null) throw new WebException(WebExceptionCode.PARAM_NULL);
        Venue venue = this.getOne(new QueryWrapper<Venue>().eq("email", email));
        if (venue == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        venue.setPassword(password);
        this.updateById(venue);
    }

    //修改场馆信息
    @Override
    public void venueModify(Integer userId, ModifyVenueForm modifyVenueForm) {
        Venue venue = getById(userId);
        if (venue == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        if (!"可用".equals(venue.getState())) throw new WebException(WebExceptionCode.USER_IS_NOT_AVAILABLE);
        String rawAccount_name = modifyVenueForm.getAccountName();// 要修改的场馆账号名
        String username = venue.getAccountName();// 原场馆账号名
        if (rawAccount_name != null && !rawAccount_name.equals(username)) {
            // 如果要修改场馆账号名 需要检查是否有重名
            Venue user = this.getOne(new QueryWrapper<Venue>().eq("account_name", rawAccount_name));
            if (user != null) throw new WebException(WebExceptionCode.USERNAME_EXISTS);
        }
        venue.setAccountName(rawAccount_name);//场馆账号名
        venue.setName(modifyVenueForm.getName());//场馆姓名
        venue.setAddress(modifyVenueForm.getAddress());//场馆地址
        venue.setLongitude(modifyVenueForm.getLongitude());//场馆经度
        venue.setLatitude(modifyVenueForm.getLatitude());//场馆维度
        venue.setPhone(modifyVenueForm.getPhone());//场馆电话
        updateById(venue);
    }


    //获取场馆所有信息
    @Override
    public VenueDto getUserInfo(Integer userId) {
        Venue venue = this.getById(userId);
        if (venue == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        return BeanCopyUtil.copyObject(venue, VenueDto.class);
    }

    @Override
    public IPage<Venue> findAll(Page<Venue> pageInfo) {
        return this.baseMapper.list(pageInfo);
    }

    @Override
    public Page<VenueDto> getAllVenue(String condition, Integer current, Integer size) {
        log.info("condition{},current{},size{}",condition,current,size);
        //配置分页片段
        Page<Venue> page = new Page<>(current == null ? 1 : current, size == null ? 4 : size);
        //配置queryWrapper
        QueryWrapper<Venue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("state", "可用");
        //判断condition是否为空，为空则findAll,不为空则条件查询
        if(condition!=null&&!condition.trim().equals("")){
            queryWrapper.eq("name", condition)   //条件查询
                    .or().like("address", condition)   //模糊查询
                    .or().eq("phone", condition)
                    .or().eq("account_name", condition)
                    .or().eq("email", condition);
        }
//        if (!"".equals(condition) || condition != null) {
//            //配置queryWrapper查询条件
//
//
//        }
        //生成分页
        Page<Venue> venuePage = venueDao.selectPage(page, queryWrapper);
        List<Venue> records = venuePage.getRecords();
        //List<VenueDto> VenueDtos=new ArrayList<>();

        List<VenueDto> venueDtos = BeanUtil.copyToList(records, VenueDto.class);
        for (int i = 0; i < records.size(); i++) {
            Integer venueId = records.get(i).getVenueId();
            log.info("场馆id为{}",venueId);
            String link = picService.query().eq("venue_id", venueId).one().getLink();
            venueDtos.get(i).setLink(link);
            continue;
        }
        Page<VenueDto> myPage=new Page<>();
        myPage.setRecords(venueDtos);
        myPage.setCurrent(venuePage.getCurrent());
        myPage.setTotal(venuePage.getTotal());
        return myPage;
    }

    @Override
    public List<Venue> findVenue() {
        List<Venue> list = venueDao.selectList(new QueryWrapper<Venue>().eq("state", "可用"));
        return list;
    }


    private void saveCode(String email, String code) {
        //通过redisTemplate获取操作redis的接口对象
        ValueOperations<String, String> operations = redisTemplate.opsForValue();
        operations.set(email, code, 10 * 60, TimeUnit.SECONDS);// 设置10分钟过期
    }
}
